<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style>
    
  </style>
</head>
<body>
  <div class="app">
    我的名字是：{{ name }}<br>
    我的名字是：{{ name }}<br>
    我的性别是：<b>{{ sex }}</b><br>
    我的年龄是：<em>{{ age }}</em><br>
    我的性别是：<b>{{   sex  }}</b><br>
    我的年龄是：<em>{{ age }}</em><br>
  </div>
</body>
<script>
  // 自定义封装Vue的基本功能：响应式数据，能拦截数据的修改，同步修改对应的DOM内容

  const vm = myVue({
    data:{
      name:"张三",
      age:"20",
      sex:"男"
    },
    element:".app"
  });

  console.log(vm);
  console.log(vm.name); // 张三
  // vm.name = "admin";
  // vm.age = "admin";
  // vm.sex = "admin";

  function myVue(ops={}){
    const {data={}, element=""} = ops;
    // 1. 获取要控制的容器
    const app = document.querySelector(element);
    // 2. 获取容器内容，作为原始字符
    let str = app.innerHTML;
    // 从页面结构中挑出需要被替换的字符 的正则
    let reg = /{{\s*([a-z_$][\w$]*)\s*}}/g;
    // 挑出要替换的字符
    const arr = str.match(reg);
    // 从要被替换掉的字符中挑出变量名 的正则
    let nameReg = /[a-z_$][\w$]*/;
    
    // 3. 初始立即渲染一次页面（解析页面中的数据标志为真实数据）
    render(str);
    // 渲染页面的功能封装：每次渲染页面时都需要传入原始字符，在原始字符的基础上解析数据
    function render(str){
      // 遍历要被替换的字符
      arr.forEach(val=>{
        // 在要替换的字符中挑出变量名
        const n = val.match(nameReg)[0];
        // 替换原字符：根据 要被替换的字符，替换成data中对应的属性
        str = str.replace(val, data[n]);
      })
      // 将替换之后的页面结构，重新设置回页面
      app.innerHTML = str;
    }
    // 4. 数据劫持
    return new Proxy(data, {
      get(o, i){
        return o[i];
      },
      set(o, i, val){
        o[i] = val;
        // 5. 当劫持到数据发生改变时，重新渲染页面结构
        render(str);
      }
    })
  }

</script>
</html>